package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CategoryClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.AssertUtils;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.ILearningRecordService;
import org.springframework.retry.annotation.Recover;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindException;

import javax.annotation.Resource;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-06-22
 */
@Service
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {


    @Resource
    private CourseClient courseClient;

    @Resource
    private CatalogueClient catalogueClient;

//    @Resource
//    private ILearningRecordService learningRecordService; //循环依赖bug
    @Resource
    private LearningRecordMapper learningRecordMapper;

    @Override
    public void addUserLessons(Long userId, List<Long> courseIds) {

        //查询课程信息
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
        if (simpleInfoList == null || simpleInfoList.isEmpty()) {
            log.error("课程信息不存在");
            return;
        }
        //添加过期时间
        List<LearningLesson> list = new ArrayList<>();
        simpleInfoList.forEach(simpleInfo -> {
            LearningLesson lesson = new LearningLesson();

            LocalDateTime now = LocalDateTime.now();
            Integer validDuration = simpleInfo.getValidDuration();
            if (validDuration != null && validDuration > 0) {
                lesson.setCreateTime(now);
                lesson.setExpireTime(now.plusMinutes(validDuration));
            }

            lesson.setUserId(userId);
            lesson.setCourseId(simpleInfo.getId()
            );
            list.add(lesson);
        });

        //批量保存
        saveBatch(list);
    }

    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {
        //获取当前登录用户
        Long user = UserContext.getUser();
//        if (user == null) {
//            throw new BadRequestException("请先登录");
//        }

        //分页查询
        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .page(query.toMpPage("latest_learn_time", false));

        List<LearningLesson> records = page.getRecords();
        if (records == null || records.isEmpty()) {
            return PageDTO.empty(page);
        }
        // 3.查询课程信息
        List<Long> collects = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> cinfos = courseClient.getSimpleInfoList(collects);
        if (cinfos == null || cinfos.isEmpty()) {
            throw new BizIllegalException("课程不存在");
        }

        //将cinfos 课程集合转换为map结构<课程id 课程对象>
        Map<Long, CourseSimpleInfoDTO> collect = cinfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        //将po中的数据封装到vo中
        List<LearningLessonVO> list = new ArrayList<>();
        for (LearningLesson record : records) {
            LearningLessonVO learningLessonVO = BeanUtils.copyBean(record, LearningLessonVO.class);
            CourseSimpleInfoDTO courseSimpleInfoDTO = collect.get(record.getCourseId());
            if (courseSimpleInfoDTO != null) {
                learningLessonVO.setCourseName(courseSimpleInfoDTO.getName());
                learningLessonVO.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
                learningLessonVO.setSections(courseSimpleInfoDTO.getSectionNum());
            }
            list.add(learningLessonVO);
        }
        return PageDTO.of(page,list);
    }

    @Override
    public LearningLessonVO queryMyCurrentLesson() {

        Long user = UserContext.getUser();

        //查询最近一次学习的课程
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING)
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();

        if (lesson == null) {
            return null;
        }
        //远程调用课程服务，给vo中课程名 封面 章节数赋值
        CourseFullInfoDTO cinfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (cinfo == null) {
            throw new BizIllegalException("课程不存在");
        }

        //查询当前用户课程表中 总的课程数
        Integer count = this.lambdaQuery().eq(LearningLesson::getUserId, user).count();

        //远程调用课程服务 获取小节名称和小节编号
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
        if (cataSimpleInfoDTOS.isEmpty()){
            throw new BizIllegalException("小姐不存在");
        }

        //数据封装到vo
        LearningLessonVO learningLessonVO = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        learningLessonVO.setCourseName(cinfo.getName());
        learningLessonVO.setCourseCoverUrl(cinfo.getCoverUrl());
        learningLessonVO.setSections(cinfo.getSectionNum());
        learningLessonVO.setCourseAmount(count);
        learningLessonVO.setLatestSectionName(cataSimpleInfoDTOS.get(0).getName());
        learningLessonVO.setLatestSectionIndex(cataSimpleInfoDTOS.get(0).getCIndex());
        return null;
    }

    @Override
    public void deleteCourseFromLesson(Object o, Long courseId) {
        Long user = UserContext.getUser();
        remove(buildUserIdAndCourseIdWrapper(user, courseId));
    }

    @Override
    public Long isLessonVaild(Long courseId) {

        Long user = UserContext.getUser();
        //判断是否拥有课程 learning_lesson
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if (lesson == null) {
            return null;
        }
        //判断该可是是否过期
        LocalDateTime expireTime = lesson.getExpireTime();
        if (expireTime != null && expireTime.isBefore(LocalDateTime.now())) {
            return null; // 课程已过期
        }
        // 课程未过期，继续后续逻辑
        return lesson.getId();
    }

    @Override
    public LearningLessonVO queryLessonByCourseId(Long courseId) {
        Long user = UserContext.getUser();

        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if (lesson == null) {
            return null;
        }

        return BeanUtils.copyBean(lesson, LearningLessonVO.class);
    }


    private LambdaQueryWrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
        //原方法
        LambdaQueryWrapper<LearningLesson> queryWrapper = new QueryWrapper<LearningLesson>()
                .lambda()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId);

//        // 方式1：直接创建LambdaQueryWrapper
//        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>()
//                .eq(LearningLesson::getUserId, userId)
//                .eq(LearningLesson::getCourseId, courseId);

//         // 方式2：使用Wrappers工具类
//        LambdaQueryWrapper<LearningLesson> queryWrapper = Wrappers.lambdaQuery(LearningLesson.class)
//                .eq(LearningLesson::getUserId, userId)
//                .eq(LearningLesson::getCourseId, courseId);

        return queryWrapper;
    }

    @Override
    public void createLearningPlan(Long courseId, Integer freq) {
        // 1.获取当前登录的用户
        Long userId = UserContext.getUser();
        // 2.查询课表中的指定课程有关的数据
        LearningLesson lesson = lambdaQuery()
                        .eq(LearningLesson::getUserId,userId)
                        .eq(LearningLesson::getCourseId,courseId)
                                .one();
        AssertUtils.isNotNull(lesson, "课程信息不存在！");
        // 3.修改数据
        LearningLesson lessonPlan = new LearningLesson();
        lessonPlan.setId(lesson.getId());
        lessonPlan.setWeekFreq(freq);
        if(lesson.getPlanStatus() == PlanStatus.NO_PLAN) {
            lessonPlan.setPlanStatus(PlanStatus.PLAN_RUNNING);
        }
        updateById(lessonPlan);

    }

    @Override
    public LearningPlanPageVO queryMyPlans(PageQuery query) {

        Long userId = UserContext.getUser();
        //todo 2.查询积分

        //3.查询本周学习计划总数据 learning_lesson表 条件userId status in(0,1),plan_status=1
        QueryWrapper<LearningLesson> wrapper = new QueryWrapper<>();
        wrapper.select("sum(week_freq) as plansTotal");
        wrapper.eq("user_id", userId)
                .in("status", Arrays.asList(0, 1))
                .eq("plan_status", PlanStatus.PLAN_RUNNING.getValue());
        Map<String, Object> map = getMap(wrapper);

        Integer planTotal = null;
        if (map != null) {
//            planTotal = (Integer) map.get("plansTotal");  //本周计划学习
            planTotal = Optional.ofNullable(map.get("plansTotal"))
                    .map(Number.class::cast)
                    .map(Number::intValue)
                    .orElse(0); // 默认值
        }

        //4.查询本周已学习计划总数居  weekFinished
            // 获取本周起始和结束时间
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime monday = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
                .withHour(0).withMinute(0).withSecond(0);
        LocalDateTime sunday = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY))
                .withHour(23).withMinute(59).withSecond(59);

        Integer weekFinishedNum = learningRecordMapper.selectCount(Wrappers.<LearningRecord>lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getFinished, true)
                .between(LearningRecord::getFinishTime, monday, sunday)
        );

        //5.查询课表数据 list
                //5.1查询课表数据
        Page<LearningLesson> page = lambdaQuery().eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .page(query.toMpPage("latest_learn_time", false));
        
        List<LearningLesson> records = page.getRecords();
        if(CollUtils.isEmpty(records)) {
            return null;
        }
                //5.2调用课程服务  courseName  sections
        Set<Long> courseIds = records.stream()
                .map(LearningLesson::getCourseId)
                .collect(Collectors.toSet());

        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
                        //5.2.1 list转map <课程id,CourseSimpleInfoDTO>
        Map<Long, CourseSimpleInfoDTO> courseMap = simpleInfoList.stream()
                .collect(Collectors.toMap(
                        CourseSimpleInfoDTO::getId,
                        Function.identity()
                ));

                //5.3 查Record表 本周已经学习章节数目weekLearnedSections;
        QueryWrapper<LearningRecord> learningRecordQueryWrapper = new QueryWrapper<>();
        learningRecordQueryWrapper.select("lesson_id as lessonId","count(*) as userId");
        learningRecordQueryWrapper.eq("user_id",userId);
        learningRecordQueryWrapper.between("finish_time",monday,sunday);
        learningRecordQueryWrapper.groupBy("lesson_id");
        List<LearningRecord> learningRecords = learningRecordMapper.selectList(learningRecordQueryWrapper);
        Map<Long, Long> recordMap = learningRecords.stream()
                .collect(Collectors.toMap(
                        LearningRecord::getLessonId,
                       c -> c.getUserId()
                ));

        //8.封装vo返回
        LearningPlanPageVO  planPageVO = new LearningPlanPageVO();
        planPageVO.setWeekPoints(0); //TODO
        planPageVO.setWeekTotalPlan(planTotal);
        planPageVO.setWeekFinished(weekFinishedNum);

        List<LearningPlanVO> planVOList = new ArrayList<>();
        for (LearningLesson record : records) {
            LearningPlanVO planVO = BeanUtils.copyProperties(record, LearningPlanVO.class);

            CourseSimpleInfoDTO courseSimpleInfoDTO = courseMap.get(record.getCourseId());
            if(courseSimpleInfoDTO != null) {
                planVO.setCourseName(courseSimpleInfoDTO.getName());
                planVO.setSections(courseSimpleInfoDTO.getSectionNum());
            }


            planVO.setWeekLearnedSections(recordMap.getOrDefault(record.getId(),0L).intValue());
            planVOList.add(planVO);
        }
        planPageVO.setList(planVOList);

        planPageVO.setTotal(page.getTotal());
        planPageVO.setPages(page.getPages());
        return planPageVO;
    }

}
